/*
 *  Cero Project - Copyright   2006 The Cero Developement Team 
 *  (Michael Laguerre, Camille Roux, Matthieu Segret, Mathieu Sivade) 
 * 
 *  This program is free software; you can redistribute it and/or modify it 
 *  under the terms of the GNU General Public License as published by the Free 
 *  Software Foundation; either version 2 of the License, or (at your option) 
 *  any later version.
 * 
 *  This program is distributed in the hope that it will be useful, but 
 *  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 *  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 
 *  for more details.
 */

package org.ceroproject.games;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * Quite the UFO here. This class allows you to define an iterator outside the
 * collection and use it instead of the usual iterator of the class. This is to
 * be used by rules, which might need to change the order of players, skip turns
 * and such. At the moment, I couldn't find a way to parameterize the
 * implementation of Collection to use.
 * 
 * @author Telem
 * @param <CollectedType>
 *            The type of the values collected into this class
 */
@Deprecated
public class DynamicallyIteratedList<CollectedType> extends
		ArrayList<CollectedType> implements IteratorMaker<CollectedType> {

	private static final long serialVersionUID = 2530491313248265946L;

	/** The mean to get new iterators */
	private IteratorMaker<CollectedType> iteratorMaker = this;

	private OverlyingIterator currentIterator = new OverlyingIterator(
			newIterator());

	/**
	 * Sets the currently used iterator type.
	 * 
	 * @param itmaker
	 *            The IteratorMaker to use in order to get new iterators.
	 *            Passing null will result in using the default IteratorMaker.
	 */
	public void setIteratorMaker(IteratorMaker<CollectedType> itmaker) {
		iteratorMaker = (itmaker == null) ? this : itmaker;
		currentIterator.setIterator(iteratorMaker.newIterator());
	}

	/**
	 * Returns a new iterator over the values.
	 * 
	 * @return a new iterator over the values.
	 */
	public Iterator<CollectedType> iterator() {
		return currentIterator;
	}

	/**
	 * Returns a new default iterator over the values
	 * 
	 * @return a new default iterator over the values
	 */
	public Iterator<CollectedType> newIterator() {
		return super.iterator();
	}

	/**
	 * Using this iterator is double-sided : it does cost you more time on
	 * collection modification, because you will create a new Iterator each time
	 * the collection is modified, but on the other hand, this will allow the
	 * iterator type to change anytime, even though an iterator over the
	 * collection might already be in use.
	 * 
	 * @author Telem
	 */
	private class OverlyingIterator implements Iterator<CollectedType> {
		private Iterator<CollectedType> underLyingIterator;

		public OverlyingIterator(Iterator<CollectedType> it) {
			setIterator(it);
		}

		public void setIterator(Iterator<CollectedType> it) {
			if (it == null)
				throw new NullPointerException(
						"a non-null iterator needs to be passed in");
			underLyingIterator = it;
		}

		public boolean hasNext() {
			return underLyingIterator.hasNext();
		}

		public CollectedType next() {
			return underLyingIterator.next();
		}

		public void remove() {
			underLyingIterator.remove();
		}

	}

	// functions overrided to ensure the iterator is up to date

	@Override
	public boolean add(CollectedType arg0) {
		boolean result = super.add(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public void add(int arg0, CollectedType arg1) {
		super.add(arg0, arg1);
		currentIterator.setIterator(newIterator());
	}

	@Override
	public boolean addAll(Collection<? extends CollectedType> arg0) {
		boolean result = super.addAll(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public boolean addAll(int arg0, Collection<? extends CollectedType> arg1) {
		boolean result = super.addAll(arg0, arg1);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public void clear() {
		super.clear();
		currentIterator.setIterator(newIterator());
	}

	@Override
	public CollectedType remove(int arg0) {
		CollectedType result = super.remove(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public boolean remove(Object arg0) {
		boolean result = super.remove(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public boolean removeAll(Collection<?> arg0) {
		boolean result = super.removeAll(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}

	@Override
	public boolean retainAll(Collection<?> arg0) {
		boolean result = super.retainAll(arg0);
		currentIterator.setIterator(newIterator());
		return result;
	}
}
